/*
 *------------------------------------------------------------------------------
 * @File      :    imx335_mipi.c
 * @Date      :    2021-3-20
 * @Author    :    lomboswer <lomboswer@lombotech.com>
 * @Brief     :    Source file for MDP(Media Development Platform).
 *
 * Copyright (C) 2020-2021, LomboTech Co.Ltd. All rights reserved.
 *------------------------------------------------------------------------------
 */
#include "ei_comm_camera.h"

#include "camera_usr.h"

#ifdef __cplusplus
#if __cplusplus
extern "C" {
#endif
#endif /* __cplusplus */

#define SNS_ID 335
#define SNS_NAME  "imx335_mipi"
#define DEV_TYPE MCSI
#define BRL        ((1444u + 20u) * 2)
#define RHS1_MAX   (BRL * 2 - 1)
#define SHR1_MIN   18u

static VISS_DEV gaVissDev[ISP_MAX_DEV_NUM] = {-1};
static SNS_STATE_S g_sastSns[VISS_MAX_DEV_NUM];

#define WDR2TO1_DECREASING_EXP_RATIO_MODE 1
/*
    RHS1 limitation:
    8n + 2
    RHS1 < BRL*2
*/

#define VMAX_1080P (0x465)
#define VMAX_720P (0x2ee)

#define WDR2TO1_RHS1_720P (VMAX_720P*2 - 735*2 - 21)
#define WDR3TO1_RHS1_720P (0x55)
#define WDR3TO1_RHS2_720P (0x5F)

#define WDR2TO1_RHS1_1080P_DEFAULT (VMAX_1080P*2 - 1109*2 - 21)
#define WDR2TO1_RHS1_1080P (0x65)


#define WDR2TO1_LM_RATIO (16)

static const SNS_REG_S s_aRaw2592x1944p30fps4LsRaw12[] = {
    /* sensor stanby */
    {0x3000, 0x01},
    {0x3001, 0x00},
    {0x3002, 0x01},

    /* setting */
    //{0x3002, 0x00},
    {0x300C, 0x5B},// BCWAIT_TIME[7:0]
    {0x300D, 0x40},// CPWAIT_TIME[7:0]
    {0x314C, 0xC0},// INCKSEL1[8:0]
    {0x315A, 0x06},// INCKSEL2[1:0]
    {0x316A, 0x7E},// INCKSEL4[1:0]
    {0x319E, 0x02},// SYS_MODE
    {0x31A1, 0x00},// XVS_DRV[1:0]
    {0x3288, 0x21},// -
    {0x328A, 0x02},// -
    {0x3414, 0x05},// -
    {0x3416, 0x18},// -
    {0x3648, 0x01},// -
    {0x364A, 0x04},// -
    {0x364C, 0x04},// -
    {0x3678, 0x01},// -
    {0x367C, 0x31},// -
    {0x367E, 0x31},// -
    {0x3706, 0x10},// -
    {0x3708, 0x03},// -
    {0x3714, 0x02},// -
    {0x3715, 0x02},// -
    {0x3716, 0x01},// -
    {0x3717, 0x03},// -
    {0x371C, 0x3D},// -
    {0x371D, 0x3F},// -
    {0x372C, 0x00},// -
    {0x372D, 0x00},// -
    {0x372E, 0x46},// -
    {0x372F, 0x00},// -
    {0x3730, 0x89},// -
    {0x3731, 0x00},// -
    {0x3732, 0x08},// -
    {0x3733, 0x01},// -
    {0x3734, 0xFE},// -
    {0x3735, 0x05},// -
    {0x3740, 0x02},// -
    {0x375D, 0x00},// -
    {0x375E, 0x00},// -
    {0x375F, 0x11},// -
    {0x3760, 0x01},// -
    {0x3768, 0x1B},// -
    {0x3769, 0x1B},// -
    {0x376A, 0x1B},// -
    {0x376B, 0x1B},// -
    {0x376C, 0x1A},// -
    {0x376D, 0x17},// -
    {0x376E, 0x0F},// -
    {0x3776, 0x00},// -
    {0x3777, 0x00},// -
    {0x3778, 0x46},// -
    {0x3779, 0x00},// -
    {0x377A, 0x89},// -
    {0x377B, 0x00},// -
    {0x377C, 0x08},// -
    {0x377D, 0x01},// -
    {0x377E, 0x23},// -
    {0x377F, 0x02},// -
    {0x3780, 0xD9},// -
    {0x3781, 0x03},// -
    {0x3782, 0xF5},// -
    {0x3783, 0x06},// -
    {0x3784, 0xA5},// -
    {0x3788, 0x0F},// -
    {0x378A, 0xD9},// -
    {0x378B, 0x03},// -
    {0x378C, 0xEB},// -
    {0x378D, 0x05},// -
    {0x378E, 0x87},// -
    {0x378F, 0x06},// -
    {0x3790, 0xF5},// -
    {0x3792, 0x43},// -
    {0x3794, 0x7A},// -
    {0x3796, 0xA1},// -
    {0x3A18, 0x7F},// TCLKPOST[9:0]
    {0x3A1A, 0x37},// TCLKPREPARE[9:0]
    {0x3A1C, 0x37},// TCLKTRAIL[9:0]
    {0x3A1E, 0xF7},// TCLKZERO[9:0]
    {0x3A1F, 0x00},//
    {0x3A20, 0x3F},// THSPREPARE[9:0]
    {0x3A22, 0x6F},// THSZERO[9:0]
    {0x3A24, 0x3F},// THSTRAIL[9:0]
    {0x3A26, 0x5F},// THSEXIT[9:0]
    {0x3A28, 0x2F},// TLPX[9:0]

    /* stanby cancel */
    /* 0x3000, 0x00, */
    /* 0x3001, 0x00, */
    /* 0x3002, 0x00, */

};

/*
 * IMX335LQN Window cropping 2568x1444 CSI-2_2lane 1188Mbps AD:10bit Output:10bit 37.125Mhz Master Mode 30fps
 * Tool ver : Ver8.0
 */
static const SNS_REG_S s_aRaw2568x1444p30fps2LsRaw10[] = {
    {0x3002, 0x00},  //modify by zsy
    {0x300C, 0x5B},  // BCWAIT_TIME[7:0]
    {0x300D, 0x40},  // CPWAIT_TIME[7:0]
    {0x3018, 0x04},  // WINMODE[3:0]
    {0x302C, 0x48},  // HTRIMMING_START[11:0]
    {0x302E, 0x08},  // HNUM[11:0]
    {0x3050, 0x00},  // ADBIT[0]
    {0x3056, 0xA4},  // Y_OUT_SIZE[12:0]
    {0x3057, 0x05},  //
    {0x3074, 0xB8},  // AREA3_ST_ADR_1[12:0]
    {0x3075, 0x02},  //
    {0x3076, 0x48},  // AREA3_WIDTH_1[12:0]
    {0x3077, 0x0B},  //
    {0x30C6, 0x12},  // BLACK_OFSET_ADR[12:0]
    {0x30CE, 0x64},  // UNRD_LINE_MAX[12:0]
    {0x30D8, 0xD0},  // UNREAD_ED_ADR[12:0]
    {0x30D9, 0x0E},  //
    {0x315A, 0x02},  // INCKSEL2[1:0]
    {0x316A, 0x7E},  // INCKSEL4[1:0]
    {0x319D, 0x00},  // MDBIT
    {0x31A1, 0x00},  // XVS_DRV[1:0]
    {0x3288, 0x21},  // -
    {0x328A, 0x02},  // -
    {0x3414, 0x05},  // -
    {0x3416, 0x18},  // -
    {0x341C, 0xFF},  // ADBIT1[8:0]
    {0x341D, 0x01},  //
    {0x3648, 0x01},  // -
    {0x364A, 0x04},  // -
    {0x364C, 0x04},  // -
    {0x3678, 0x01},  // -
    {0x367C, 0x31},  // -
    {0x367E, 0x31},  // -
    {0x3706, 0x10},  // -
    {0x3708, 0x03},  // -
    {0x3714, 0x02},  // -
    {0x3715, 0x02},  // -
    {0x3716, 0x01},  // -
    {0x3717, 0x03},  // -
    {0x371C, 0x3D},  // -
    {0x371D, 0x3F},  // -
    {0x372C, 0x00},  // -
    {0x372D, 0x00},  // -
    {0x372E, 0x46},  // -
    {0x372F, 0x00},  // -
    {0x3730, 0x89},  // -
    {0x3731, 0x00},  // -
    {0x3732, 0x08},  // -
    {0x3733, 0x01},  // -
    {0x3734, 0xFE},  // -
    {0x3735, 0x05},  // -
    {0x3740, 0x02},  // -
    {0x375D, 0x00},  // -
    {0x375E, 0x00},  // -
    {0x375F, 0x11},  // -
    {0x3760, 0x01},  // -
    {0x3768, 0x1A},  // -
    {0x3769, 0x1A},  // -
    {0x376A, 0x1A},  // -
    {0x376B, 0x1A},  // -
    {0x376C, 0x1A},  // -
    {0x376D, 0x17},  // -
    {0x376E, 0x0F},  // -
    {0x3776, 0x00},  // -
    {0x3777, 0x00},  // -
    {0x3778, 0x46},  // -
    {0x3779, 0x00},  // -
    {0x377A, 0x89},  // -
    {0x377B, 0x00},  // -
    {0x377C, 0x08},  // -
    {0x377D, 0x01},  // -
    {0x377E, 0x23},  // -
    {0x377F, 0x02},  // -
    {0x3780, 0xD9},  // -
    {0x3781, 0x03},  // -
    {0x3782, 0xF5},  // -
    {0x3783, 0x06},  // -
    {0x3784, 0xA5},  // -
    {0x3788, 0x0F},  // -
    {0x378A, 0xD9},  // -
    {0x378B, 0x03},  // -
    {0x378C, 0xEB},  // -
    {0x378D, 0x05},  // -
    {0x378E, 0x87},  // -
    {0x378F, 0x06},  // -
    {0x3790, 0xF5},  // -
    {0x3792, 0x43},  // -
    {0x3794, 0x7A},  // -
    {0x3796, 0xA1},  // -
    {0x3A01, 0x01},  // LANEMODE[2:0]
};

/*
 * IMX335LQN Window cropping 2592x1944 CSI-2_2lane 1188Mbps AD:10bit Output:10bit 37.125Mhz Master Mode 30fps
 * Tool ver : Ver8.0  created by tbl accroding to IMX335LQN Window cropping 2568x1444
 */
static const SNS_REG_S s_aRaw2592x1944p30fps2LsRaw10[] = {
    {0x3002, 0x00},  //modify by zsy
    {0x300C, 0x5B},  // BCWAIT_TIME[7:0]
    {0x300D, 0x40},  // CPWAIT_TIME[7:0]
    {0x3050, 0x00},  // ADBIT[0]
    {0x315A, 0x02},  // INCKSEL2[1:0]
    {0x316A, 0x7E},  // INCKSEL4[1:0]
    {0x319D, 0x00},  // MDBIT
    {0x31A1, 0x00},  // XVS_DRV[1:0]
    {0x3288, 0x21},  // -
    {0x328A, 0x02},  // -
    {0x3414, 0x05},  // -
    {0x3416, 0x18},  // -
    {0x341C, 0xFF},  // ADBIT1[8:0]
    {0x341D, 0x01},  //
    {0x3648, 0x01},  // -
    {0x364A, 0x04},  // -
    {0x364C, 0x04},  // -
    {0x3678, 0x01},  // -
    {0x367C, 0x31},  // -
    {0x367E, 0x31},  // -
    {0x3706, 0x10},  // -
    {0x3708, 0x03},  // -
    {0x3714, 0x02},  // -
    {0x3715, 0x02},  // -
    {0x3716, 0x01},  // -
    {0x3717, 0x03},  // -
    {0x371C, 0x3D},  // -
    {0x371D, 0x3F},  // -
    {0x372C, 0x00},  // -
    {0x372D, 0x00},  // -
    {0x372E, 0x46},  // -
    {0x372F, 0x00},  // -
    {0x3730, 0x89},  // -
    {0x3731, 0x00},  // -
    {0x3732, 0x08},  // -
    {0x3733, 0x01},  // -
    {0x3734, 0xFE},  // -
    {0x3735, 0x05},  // -
    {0x3740, 0x02},  // -
    {0x375D, 0x00},  // -
    {0x375E, 0x00},  // -
    {0x375F, 0x11},  // -
    {0x3760, 0x01},  // -
    {0x3768, 0x1A},  // -
    {0x3769, 0x1A},  // -
    {0x376A, 0x1A},  // -
    {0x376B, 0x1A},  // -
    {0x376C, 0x1A},  // -
    {0x376D, 0x17},  // -
    {0x376E, 0x0F},  // -
    {0x3776, 0x00},  // -
    {0x3777, 0x00},  // -
    {0x3778, 0x46},  // -
    {0x3779, 0x00},  // -
    {0x377A, 0x89},  // -
    {0x377B, 0x00},  // -
    {0x377C, 0x08},  // -
    {0x377D, 0x01},  // -
    {0x377E, 0x23},  // -
    {0x377F, 0x02},  // -
    {0x3780, 0xD9},  // -
    {0x3781, 0x03},  // -
    {0x3782, 0xF5},  // -
    {0x3783, 0x06},  // -
    {0x3784, 0xA5},  // -
    {0x3788, 0x0F},  // -
    {0x378A, 0xD9},  // -
    {0x378B, 0x03},  // -
    {0x378C, 0xEB},  // -
    {0x378D, 0x05},  // -
    {0x378E, 0x87},  // -
    {0x378F, 0x06},  // -
    {0x3790, 0xF5},  // -
    {0x3792, 0x43},  // -
    {0x3794, 0x7A},  // -
    {0x3796, 0xA1},  // -
    {0x3A01, 0x01},  // LANEMODE[2:0]
};

/*
 * 4lane init
 * raw10
 * 2560*1440 30fps
 */
static const SNS_REG_S s_aRaw1440p2fdol30fps4Lane[] = {
    /* sensor stanby */
    {0x3000, 0x01},
    {0x3001, 0x00},
    {0x3002, 0x01},

    /* setting */
    //{0x3002, 0x00},
    {0x300C, 0x5B},// BCWAIT_TIME[7:0]
    {0x300D, 0x40},// CPWAIT_TIME[7:0]
    {0x3034, 0x13},// HMAX[15:0]
    {0x3035, 0x01},//
    {0x3048, 0x01},// WDMODE[0]
    {0x3049, 0x01},// WDSEL[1:0]
    {0x304A, 0x04},// WD_SET1[2:0]
    {0x304B, 0x03},// WD_SET2[3:0]
    {0x304C, 0x13},// OPB_SIZE_V[5:0]
    {0x3050, 0x00},// ADBIT[0]
    {0x3058, 0x68},// SHR0[19:0]
    {0x3059, 0x01},//
    {0x3068, 0x4A},// RHS1[19:0]
    {0x315A, 0x02},// INCKSEL2[1:0]
    {0x316A, 0x7E},// INCKSEL4[1:0]
    {0x319D, 0x00},// MDBIT
    {0x31A1, 0x00},// XVS_DRV[1:0]
    {0x31D7, 0x01},// XVSMSKCNT_INT[1:0]
    {0x3288, 0x21},// -
    {0x328A, 0x02},// -
    {0x3414, 0x05},// -
    {0x3416, 0x18},// -
    {0x341C, 0xFF},// ADBIT1[8:0]
    {0x341D, 0x01},//
    {0x3648, 0x01},// -
    {0x364A, 0x04},// -
    {0x364C, 0x04},// -
    {0x3678, 0x01},// -
    {0x367C, 0x31},// -
    {0x367E, 0x31},// -
    {0x3706, 0x10},// -
    {0x3708, 0x03},// -
    {0x3714, 0x02},// -
    {0x3715, 0x02},// -
    {0x3716, 0x01},// -
    {0x3717, 0x03},// -
    {0x371C, 0x3D},// -
    {0x371D, 0x3F},// -
    {0x372C, 0x00},// -
    {0x372D, 0x00},// -
    {0x372E, 0x46},// -
    {0x372F, 0x00},// -
    {0x3730, 0x89},// -
    {0x3731, 0x00},// -
    {0x3732, 0x08},// -
    {0x3733, 0x01},// -
    {0x3734, 0xFE},// -
    {0x3735, 0x05},// -
    {0x3740, 0x02},// -
    {0x375D, 0x00},// -
    {0x375E, 0x00},// -
    {0x375F, 0x11},// -
    {0x3760, 0x01},// -
    {0x3768, 0x1B},// -
    {0x3769, 0x1B},// -
    {0x376A, 0x1B},// -
    {0x376B, 0x1B},// -
    {0x376C, 0x1A},// -
    {0x376D, 0x17},// -
    {0x376E, 0x0F},// -
    {0x3776, 0x00},// -
    {0x3777, 0x00},// -
    {0x3778, 0x46},// -
    {0x3779, 0x00},// -
    {0x377A, 0x89},// -
    {0x377B, 0x00},// -
    {0x377C, 0x08},// -
    {0x377D, 0x01},// -
    {0x377E, 0x23},// -
    {0x377F, 0x02},// -
    {0x3780, 0xD9},// -
    {0x3781, 0x03},// -
    {0x3782, 0xF5},// -
    {0x3783, 0x06},// -
    {0x3784, 0xA5},// -
    {0x3788, 0x0F},// -
    {0x378A, 0xD9},// -
    {0x378B, 0x03},// -
    {0x378C, 0xEB},// -
    {0x378D, 0x05},// -
    {0x378E, 0x87},// -
    {0x378F, 0x06},// -
    {0x3790, 0xF5},// -
    {0x3792, 0x43},// -
    {0x3794, 0x7A},// -
    {0x3796, 0xA1},// -

    /* stanby cancel */
    /* 0x3000, 0x00, */
    /* 0x3001, 0x00, */
    /* 0x3002, 0x00, */
};

static const SNS_REG_S s_aRaw1444p2fdol25fps2Lane[] = {
    {0x300C, 0x5B},
    {0x300D, 0x40},
    {0x3018, 0x04},
    {0x302C, 0x48},
    {0x302E, 0x08},
    {0x3030, 0xB8},
    {0x3031, 0x0B},
    {0x3034, 0xEF},
    {0x3035, 0x01},
    {0x3048, 0x01},
    {0x3049, 0x01},
    {0x304A, 0x04},
    {0x304B, 0x03},
    {0x304C, 0x13},
    {0x3050, 0x00},
    {0x3056, 0xA4},
    {0x3057, 0x05},
    {0x3058, 0x10},
    {0x3059, 0x0E},
    {0x3068, 0xAA},
    {0x3074, 0xB8},
    {0x3075, 0x02},
    {0x3076, 0x48},
    {0x3077, 0x0B},
    {0x30C6, 0x12},
    {0x30CE, 0x64},
    {0x30D8, 0xD0},
    {0x30D9, 0x0E},
    {0x315A, 0x02},
    {0x316A, 0x7E},
    {0x319D, 0x00},
    {0x31A1, 0x00},
    {0x31D7, 0x01},
    {0x3288, 0x21},
    {0x328A, 0x02},
    {0x3414, 0x05},
    {0x3416, 0x18},
    {0x341C, 0xFF},
    {0x341D, 0x01},
    {0x3648, 0x01},
    {0x364A, 0x04},
    {0x364C, 0x04},
    {0x3678, 0x01},
    {0x367C, 0x31},
    {0x367E, 0x31},
    {0x3706, 0x10},
    {0x3708, 0x03},
    {0x3714, 0x02},
    {0x3715, 0x02},
    {0x3716, 0x01},
    {0x3717, 0x03},
    {0x371C, 0x3D},
    {0x371D, 0x3F},
    {0x372C, 0x00},
    {0x372D, 0x00},
    {0x372E, 0x46},
    {0x372F, 0x00},
    {0x3730, 0x89},
    {0x3731, 0x00},
    {0x3732, 0x08},
    {0x3733, 0x01},
    {0x3734, 0xFE},
    {0x3735, 0x05},
    {0x3740, 0x02},
    {0x375D, 0x00},
    {0x375E, 0x00},
    {0x375F, 0x11},
    {0x3760, 0x01},
    {0x3768, 0x1A},
    {0x3769, 0x1A},
    {0x376A, 0x1A},
    {0x376B, 0x1A},
    {0x376C, 0x1A},
    {0x376D, 0x17},
    {0x376E, 0x0F},
    {0x3776, 0x00},
    {0x3777, 0x00},
    {0x3778, 0x46},
    {0x3779, 0x00},
    {0x377A, 0x89},
    {0x377B, 0x00},
    {0x377C, 0x08},
    {0x377D, 0x01},
    {0x377E, 0x23},
    {0x377F, 0x02},
    {0x3780, 0xD9},
    {0x3781, 0x03},
    {0x3782, 0xF5},
    {0x3783, 0x06},
    {0x3784, 0xA5},
    {0x3788, 0x0F},
    {0x378A, 0xD9},
    {0x378B, 0x03},
    {0x378C, 0xEB},
    {0x378D, 0x05},
    {0x378E, 0x87},
    {0x378F, 0x06},
    {0x3790, 0xF5},
    {0x3792, 0x43},
    {0x3794, 0x7A},
    {0x3796, 0xA1},
    {0x3A01, 0x01},
    {0x3302, 0x3c},
};

static CAMERA_POWER_ACT_S s_stPowerUpAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},
    {SNS_RESET, SNS_UP},
    {SNS_DELAY, 20},
};

static CAMERA_POWER_ACT_S s_sPowerDownAct[] = {
    {SNS_RESET, SNS_DOWN},
    {SNS_DELAY, 10},

};

/*
 * Imx335 support mode see datasheet page 49
 * VTS: 0x3032 0x3031 0x3030 , H M L , Default 01194H
 * HTS: 0x3035 0x3034 , H L , Default 0226H
 */
static SNS_TYPE_ATTR_S s_astSnsAttr[] = {
    {
        .enSnsType                  = IMX335_MIPI_2592_1944_30FPS_RAW12_4LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_12BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2592, 1944},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 4500,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw2592x1944p30fps4LsRaw12,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2592x1944p30fps4LsRaw12),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 891000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2592_1944_25FPS_RAW12_4LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_12BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2592, 1944},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 5400,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw2592x1944p30fps4LsRaw12,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2592x1944p30fps4LsRaw12),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 891000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2568_1444_30FPS_RAW10_2LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2560, 1440},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 4500,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw2568x1444p30fps2LsRaw10,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2568x1444p30fps2LsRaw10),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2568_1444_25FPS_RAW10_2LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2560, 1440},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 5400,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw2568x1444p30fps2LsRaw10,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2568x1444p30fps2LsRaw10),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2592_1944_30FPS_RAW10_2LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2592, 1944},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 4500,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw2592x1944p30fps2LsRaw10,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2592x1944p30fps2LsRaw10),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2592_1944_25FPS_RAW10_2LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2592, 1944},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 5400,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw2592x1944p30fps2LsRaw10,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2592x1944p30fps2LsRaw10),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2560_1440_30FPS_RAW10_2LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2560, 1440},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 4500,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw2568x1444p30fps2LsRaw10,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2568x1444p30fps2LsRaw10),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2560_1440_25FPS_RAW10_2LANE,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 297000000,

        .stSize                     = {2560, 1440},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_1Chn,

        .u32IspClk                  = 184000000,
        .u32IppuClk                 = 298000000,
        .u32Pclk                    = 74250000,
        .u32Vts                     = 5400,
        .u32Hts                     = 550,
        .enIspWdrMode               = WDR_MODE_NONE,

        .u32FrameRate               = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw2568x1444p30fps2LsRaw10,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw2568x1444p30fps2LsRaw10),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2560_1440_2TO1_30FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 396000000,
        .stSize                     = {2560, 1440},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_2Chn,
        .enWdrMode                  = VISS_WDR_MODE_VC,
        .u32IspClk                  = 198000000,
        .u32IppuClk                 = 298000000,

        .u32Pclk                    = 74250000,
        .u32Vts                     = 4500,
        .u32Hts                     = 275,
        .enIspWdrMode               = WDR_MODE_2TO1_FRAME,

        .u32FrameRate                = 30,
        .astRegCfgs[0].pstRegs      = s_aRaw1440p2fdol30fps4Lane,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1440p2fdol30fps4Lane),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_4Lane,
    },
    {
        .enSnsType                  = IMX335_MIPI_2568_1444_2TO1_25FPS_RAW10,
        .enPixelFormat              = PIX_FMT_RGB_BAYER_10BITS,
        .enRgbSeq                   = VISS_RGB_SEQ_RGGB,
        .u32ModuleClk               = 396000000,
        .stSize                     = {2560, 1440},
        .u32Mclock                  = 37125000,
        .enWorkMode                 = VISS_WORK_MODE_2Chn,
        .enWdrMode                  = VISS_WDR_MODE_VC,
        .u32IspClk                  = 198000000,
        .u32IppuClk                 = 198000000,

        .u32Pclk                    = 74250000,
        .u32Vts                     = 3000,
        .u32Hts                     = 495,
        .enIspWdrMode               = WDR_MODE_2TO1_FRAME,

        .u32FrameRate                = 25,
        .astRegCfgs[0].pstRegs      = s_aRaw1444p2fdol25fps2Lane,
        .astRegCfgs[0].u32RegsCnt   = ARRAY_SIZE(s_aRaw1444p2fdol25fps2Lane),

        .stDevCfg.stMcsiCfg.u32PhyFreq  = 1188000000,
        .stDevCfg.stMcsiCfg.enDlanes    = VISS_LANE_NUM_2Lane,
    }
};

static int CAMERA_SetI2cInfo(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    if (pstSnsState->stI2cInfo.fd > 0) {
        return EI_SUCCESS;
    }

    pstSnsState->stI2cInfo.u8RegBits = 16;
    pstSnsState->stI2cInfo.u8ValBits = 8;
    pstSnsState->stI2cInfo.u16I2cBusNum = 4;
    pstSnsState->stI2cInfo.u16I2cDevAddr = 0x1a;
    pstSnsState->pcName = SNS_NAME;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Detect(VISS_DEV VissDev)
{
    EI_U8 u8Tmp;
    EI_S32 s32Ret = EI_SUCCESS;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;

    CAMERA_CHECK_POINTER(pstI2cInfo->pfnReadReg);
    s32Ret = pstI2cInfo->pfnReadReg(pstSnsState, 0x300C, &u8Tmp);
    if (s32Ret != 0) {
        PRT_VISS_ERR("tmp[0]=%x\n", u8Tmp);
        return EI_FAILURE;
    }

     if (u8Tmp == 0xb6) {
        PRT_VISS_INFO("%s ID = 0x%04x, real sensor is imx335!\n", SNS_NAME, u8Tmp);
    } else {
        PRT_VISS_ERR("%s ID wrong! (0x%04x != 0xe0)\n", SNS_NAME, u8Tmp);
        return EI_FAILURE;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_Stream(VISS_DEV dev, EI_BOOL bOn)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    PRT_VISS_ERR("%s CAMERA_Stream******%d\n", SNS_NAME, bOn);

    if (bOn) {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3000, 0x00);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3001, 0x00);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3002, 0x00);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    } else {
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3000, 0x01);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3001, 0x01);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
        s32Ret = pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3002, 0x01);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("CAMERA_Stream*******%d\n", bOn);
        }
    }
    return s32Ret;

}

/* The following functions can be modified as needed */

static int CAMERA_I2cInit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    int ret = EI_SUCCESS;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    ret = CAMERA_SetI2cInfo(dev);
    CAMERA_CHECK_SUCCESS(ret);

    ret = CAMERA_I2C_Reg_Ops(&pstSnsState->stI2cInfo);
    CAMERA_CHECK_SUCCESS(ret);

    return EI_SUCCESS;
}

static int CAMERA_I2cExit(VISS_DEV dev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_PowerUp(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    MI_VISS_SnsPower(VissDev, 0xa0000000);
    CAMERA_SensorPowerUp(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_PowerDown(VISS_DEV VissDev)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(VissDev, pstSnsState);

    MI_VISS_SnsPower(VissDev, 0x00000000);

    CAMERA_SensorPowerDown(VissDev, pstSnsState);

    return 0;
}

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain);
static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime);

static EI_S32 CAMERA_Init(VISS_DEV dev)
{
    EI_U32 j;
    const SNS_TYPE_ATTR_S *pstSnsType;
    SNS_STATE_S *pstSnsState = EI_NULL;
    I2C_INFO_S *pstI2cInfo = EI_NULL;
    EI_S32 s32Ret;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsType = pstSnsState->pstSnsAttr;
    pstI2cInfo = &pstSnsState->stI2cInfo;

    for (j = 0; j < MAX_COF; j++) {
        s32Ret = pstSnsState->stI2cInfo.pfnwriteRegList(pstSnsState,
                pstSnsType->astRegCfgs[j].pstRegs, pstSnsType->astRegCfgs[j].u32RegsCnt);
        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("%s writeRegList err\n", SNS_NAME);
            return s32Ret;
        }
    }

    if((pstSnsType->enSnsType == IMX335_MIPI_2592_1944_25FPS_RAW12_4LANE) ||
        (pstSnsType->enSnsType == IMX335_MIPI_2592_1944_25FPS_RAW10_2LANE) ||
        (pstSnsType->enSnsType == IMX335_MIPI_2568_1444_25FPS_RAW10_2LANE) ||
        (pstSnsType->enSnsType == IMX335_MIPI_2560_1440_25FPS_RAW10_2LANE)) {
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3031, (pstSnsType->u32Vts >> 8) & 0xff);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3030, pstSnsType->u32Vts & 0xff);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3035, (pstSnsType->u32Hts >> 8) & 0xff);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3034, pstSnsType->u32Hts & 0xff);
        if (s32Ret != 0) {
            PRT_VISS_ERR("CAMERA_Init error\n");
            return s32Ret;
        }
    }

    if ((pstSnsState->afIntTime[0] > 0.000001) && (pstSnsState->fGain >= 1.0)) {
        CAMERA_SetExpTime(pstSnsState->IspDev, pstSnsState->afIntTime);
        CAMERA_SetGain(pstSnsState->IspDev, pstSnsState->fGain);
    }

    PRT_VISS_INFO("%s writeRegList success\n", SNS_NAME);

    return s32Ret;
}

static void CAMERA_Exit(VISS_DEV dev)
{
    CAMERA_I2cExit(dev);

    return;
}

static EI_S32 CAMERA_SetImageMode(VISS_DEV dev, SNS_TYPE_E enSnsType)
{
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstSnsState->enSnsType = enSnsType;
    pstSnsState->bSyncInit = EI_FALSE;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_EnumSnstype(VISS_DEV VissDev, EI_U32 u32Index, SNS_TYPE_E *peSnstype)
{
    const SNS_TYPE_ATTR_S *pstSnsType;

    if (u32Index >= ARRAY_SIZE(s_astSnsAttr))
        return EN_ERR_NO_FOUND;

    pstSnsType = &s_astSnsAttr[u32Index];

    *peSnstype = pstSnsType->enSnsType;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFrameRate(VISS_DEV VissDev, EI_FLOAT f32Fps)
{
    I2C_INFO_S *pstI2cInfo = EI_NULL;
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts;

    SNS_GET_CTX(VissDev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);

    pstI2cInfo = &pstSnsState->stI2cInfo;
    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Vts = pstSnsState->pstSnsAttr->u32Vts;

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Hts = u32Pclk / u32Vts / f32Fps;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3034, u32Hts);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3035, u32Hts >> 8);
        if (s32Ret != 0) {
            cprintf("CAMERA_Init error\n");
            return s32Ret;
        }
    } else if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        if (pstSnsState->pstSnsAttr->u32FrameRate < f32Fps || 1 > f32Fps) {
            cprintf("1 <= set fps <= %d, set fps: %f\n", pstSnsState->pstSnsAttr->u32FrameRate, f32Fps);
            f32Fps = pstSnsState->pstSnsAttr->u32FrameRate;
        }

        u32Hts = u32Pclk / u32Vts / f32Fps / 2;

        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3034, u32Hts);
        s32Ret += pstI2cInfo->pfnWriteReg(pstSnsState, 0x3035, u32Hts >> 8);
        if (s32Ret != 0) {
            cprintf("CAMERA_Init error\n");
            return s32Ret;
        }
    } else {
        return EN_ERR_NOT_SUPPORT;
    }

    pstSnsState->pstSnsAttr->u32Hts = u32Hts;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitSensorExpFunction(SENSOR_EXP_FUNC_S *pstSensorExpFunc)
{
    CAMERA_CHECK_POINTER(pstSensorExpFunc);

    memset(pstSensorExpFunc, 0, sizeof(SENSOR_EXP_FUNC_S));

    pstSensorExpFunc->pfnSensorPowerUp  = CAMERA_PowerUp;
    pstSensorExpFunc->pfnSensorPowerDown = CAMERA_PowerDown;
    pstSensorExpFunc->pfnSensorDetect   = CAMERA_Detect;
    pstSensorExpFunc->pfnSensorInit     = CAMERA_Init;
    pstSensorExpFunc->pfnSensorStream   = CAMERA_Stream;
    pstSensorExpFunc->pfnSensorExit     = CAMERA_Exit;
    pstSensorExpFunc->pfnSensorSetImageMode   = CAMERA_SetImageMode;
    pstSensorExpFunc->pfnSensorEnumSnstype   = CAMERA_EnumSnstype;
    pstSensorExpFunc->pfnSensorSetFrameRate   = CAMERA_SetFrameRate;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAeDefault(ISP_DEV dev, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_SetFps(ISP_DEV dev, EI_FLOAT f32Fps, AE_SENSOR_DEFAULT_S *pstAeSnsDft)
{
    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    CAMERA_CHECK_POINTER(pstAeSnsDft);

    return CAMERA_SetFrameRate(Dev, f32Fps);
}

static EI_S32 CAMERA_SetExpTime(ISP_DEV dev, EI_FLOAT *afIntTime)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Pclk, u32Hts, u32Vts;
    EI_U32 shutter_time;
    EI_U32 shr0, shr1;
    EI_U32 rhs1, u32fsc, rhs1_min, rhs1_max;
    EI_U32 mexp, lexp, u32mexp_delta, u32rhs1_limit;
    VISS_DEV Dev;
    static EI_U32 mexp_last;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    CAMERA_CHECK_POINTER(afIntTime);
    pstSnsState->afIntTime[0] = afIntTime[0];
    pstSnsState->afIntTime[1] = afIntTime[1];
    pstSnsState->afIntTime[2] = afIntTime[2];
    pstSnsState->afIntTime[3] = afIntTime[3];
    pstSnsState->IspDev = dev;
    CAMERA_CHECK_POWERON(pstSnsState);

    u32Pclk = pstSnsState->pstSnsAttr->u32Pclk;
    u32Hts = pstSnsState->pstSnsAttr->u32Hts;
    u32Vts = pstSnsState->pstSnsAttr->u32Vts;

    if ((u32Pclk == 0) || (u32Hts == 0) || (u32Vts == 0)) {
        PRT_VISS_ERR("error! u32Pclk %d, u32Hts %d, u32Vts %d\n", u32Pclk, u32Hts, u32Vts);
        return EI_FAILURE;
    }

    /* afIntTime[0] long/medium/short/vshort exptime (s) */
    shutter_time = afIntTime[0] * u32Pclk / u32Hts;
    if (shutter_time < 4)
        shutter_time = 4;

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_NONE) {
        if (shutter_time > u32Vts - 9)
            shutter_time = u32Vts - 9;

        shr0 = u32Vts - shutter_time;

        shr0 = shr0 < 9 ? 9 : shr0;

        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3058, (shr0 >> 0) & 0x0ff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3059, (shr0 >> 8) & 0x0ff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x305a, (shr0 >> 16) & 0x0f);

        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("\n");
        }
    } else if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {

        u32fsc = 2 * u32Vts;

        if (afIntTime[1] < 1)
            afIntTime[1] = WDR2TO1_LM_RATIO;

        mexp = shutter_time / (afIntTime[1] + 1);
        lexp = shutter_time / (afIntTime[1] + 1) * afIntTime[1];

        if (mexp_last > mexp) {
            u32mexp_delta = mexp_last - mexp;
            u32rhs1_limit = (u32fsc - (BRL * 2) - 2);
            if (u32mexp_delta > u32rhs1_limit) {
                mexp = mexp_last - (u32rhs1_limit - (u32rhs1_limit % 8));
                lexp = mexp * afIntTime[1];
            }
        }

        shr0 = u32fsc - lexp;

        rhs1_max = EI_MIN2(RHS1_MAX, shr0 - SHR1_MIN);
        rhs1_max = (rhs1_max & ~0x7) + 2;
        rhs1_min = (SHR1_MIN + 4u + 7u) / 8 * 8 + 2;

        rhs1 = SHR1_MIN + mexp;
        rhs1 = (rhs1 + 7u) / 8 * 8 + 2; /* to 8n + 2 */
        if (rhs1 > rhs1_max)
            rhs1 = rhs1_max;
        if (rhs1 < rhs1_min)
            rhs1 = rhs1_min;

        if (rhs1 <= SHR1_MIN + mexp) {
            shr1 = SHR1_MIN;
            mexp = rhs1 - shr1;
            lexp = mexp * afIntTime[1];
            shr0 = u32fsc - lexp;
        } else {
            shr1 = rhs1 - mexp;
        }

        shr1 = (shr1 & ~0x3) + 2; /* to 4n + 2 */

        if(shr1 < SHR1_MIN)
            shr1 = SHR1_MIN;

        if (shr0 < rhs1 + 18)
            shr0 = rhs1 + 18;
        else if (shr0 > u32fsc - 4)
            shr0 = u32fsc - 4;

        shr0 &= (~0x3);  /* align with 4 */

        shutter_time = lexp * (afIntTime[1] + 1) / afIntTime[1];

       /* printf("2in1 lexp:%d, mexp:%d, shr0:%d, shr1:%d, rhs1:%d\n", lexp, mexp, shr0, shr1, rhs1); */
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3058, (shr0 >> 0) & 0xff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3059, (shr0 >> 8) & 0xff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x305a, (shr0 >> 16) & 0x0f);

        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x305c, (shr1 >> 0) & 0xff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x305d, (shr1 >> 8) & 0xff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x305e, (shr1 >> 16) & 0x0f);

        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3068, (rhs1 >> 0) & 0xff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3069, (rhs1 >> 8) & 0xff);
        s32Ret |= pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x306A, (rhs1 >> 16) & 0x0f);

        if (s32Ret != EI_SUCCESS) {
            PRT_VISS_ERR("\n");
        }

        mexp_last = mexp;
    }
    afIntTime[0] = (EI_FLOAT)shutter_time * u32Hts / u32Pclk; /* for gain compensation */
    if (afIntTime[0] < 0.0001)
        afIntTime[0] = 0.0001;

    return s32Ret;
}

static EI_U32 GainTable[241] = {
    1024,   1059,   1097,   1135,   1175,   1217,   1259,   1304,   1349,   1397,   1446,   1497,   1549,   1604, //3.9dB
    1660,   1719,   1779,   1842,   1906,   1973,   2043,   2114,   2189,   2266,   2345,   2428,   2513,   2601, //8.1dB
    2693,   2788,   2886,   2987,   3092,   3201,   3313,   3430,   3550,   3675,   3804,   3938,   4076,   4219, //12.3dB
    4368,   4521,   4680,   4845,   5015,   5191,   5374,   5562,   5758,   5960,   6170,   6387,   6611,   6843, //16.5dB
    7084,   7333,   7591,   7857,   8133,   8419,   8715,   9021,   9338,   9667,  10006,  10358,  10722,  11099, //20.7dB
    11489,  11893,  12311,  12743,  13191,  13655,  14135,  14631,  15146,  15678,  16229,  16799,  17390,  18001, //24.9dB
    18633,  19288,  19966,  20668,  21394,  22146,  22924,  23730,  24564,  25427,  26320,  27245,  28203,  29194, //29.1dB
    30220,  31282,  32381,  33519,  34697,  35917,  37179,  38485,  39838,  41238,  42687,  44187,  45740,  47347, //33.3dB
    49011,  50734,  52517,  54362,  56273,  58250,  60297,  62416,  64610,  66880,  69230,  71663,  74182,  76789, //37.5dB
    79487,  82281,  85172,  88165,  91264,  94471,  97791, 101228, 104785, 108468, 112279, 116225, 120310, 124537, //41.7dB
    128914, 133444, 138134, 142988, 148013, 153215, 158599, 164172, 169942, 175914, 182096, 188495, 195119, 201976, //45.9dB
    209074, 216421, 224027, 231900, 240049, 248485, 257217, 266256, 275613, 285299, 295325, 305703, 316446, 327567, //50.1dB
    339078, 350994, 363329, 376097, 389314, 402995, 417157, 431817, 446992, 462700, 478961, 495793, 513216, 531251, //54.3dB
    549921, 569246, 589250, 609958, 631393, 653582, 676550, 700326, 724936, 750412, 776783, 804081, 832338, 861589, //58.5dB
    891867, 923209, 955652, 989236, 1024000, 1059985, 1097236, 1135795, 1175709, 1217026, 1259795, 1304067, 1349895, 1397333, //62.7dB
    1446438, 1497269, 1549887, 1604353, 1660734, 1719095, 1779508, 1842044, 1906777, 1973786, 2043149, 2114949, 2189273, 2266209, //66.9dB
    2345848, 2428287, 2513622, 2601956, 2693394, 2788046, 2886024, 2987445, 3092431, 3201105, 3313599, 3430046, 3550585, 3675361, //71.1dB
    3804521, 3938220, 4076617                                                                                        //72.0dB
};

static EI_S32 CAMERA_SetGain(ISP_DEV dev, EI_FLOAT fGain)
{
    SNS_STATE_S *pstSnsState = EI_NULL;
    EI_S32 s32Ret = EI_SUCCESS;
    EI_U32 u32Gain, db_idx;
    VISS_DEV Dev;

    SNS_GET_ISP_TO_VISS(dev, Dev);

    SNS_GET_CTX(Dev, pstSnsState);
    CAMERA_CHECK_POINTER(pstSnsState);
    pstSnsState->fGain = fGain;
    CAMERA_CHECK_POWERON(pstSnsState);

     if (fGain < 1)
        fGain = 1;

    u32Gain = fGain * 1024;

    for (db_idx = 0; db_idx < 241; db_idx++) {
        if (u32Gain <= GainTable[db_idx])
            break;
    }

    if (pstSnsState->pstSnsAttr->enIspWdrMode == WDR_MODE_2TO1_FRAME) {
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3200, ((0 >> 0) & 0x01));
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x30e8, ((db_idx >> 0) & 0xff));
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x30e9, ((db_idx >> 8) & 0x03));
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x30ea, ((db_idx >> 0) & 0xff));
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x30eb, ((db_idx >> 8) & 0x03));
    } else {
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x3200, ((1 >> 0) & 0x01));
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x30e8, ((db_idx >> 0) & 0xff));
        s32Ret += pstSnsState->stI2cInfo.pfnWriteReg(pstSnsState, 0x30e9, ((db_idx >> 8) & 0x03));
    }

    if (s32Ret != EI_SUCCESS) {
        PRT_VISS_ERR("\n");
    }

    return s32Ret;
}

static EI_S32 CAMERA_InitAeExpFunction(AE_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AE_SENSOR_EXP_FUNC_S));

    pstExpFuncs->pfnGetAeDefault    = CAMERA_GetAeDefault;
    pstExpFuncs->pfnSetFps          = CAMERA_SetFps;
    pstExpFuncs->pfnSetExpTime      = CAMERA_SetExpTime;
    pstExpFuncs->pfnSetGain         = CAMERA_SetGain;

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetAwbDefault(ISP_DEV dev, AWB_SENSOR_DEFAULT_S *pstAwbSnsDft)
{
    CAMERA_CHECK_POINTER(pstAwbSnsDft);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_InitAwbExpFunction(AWB_SENSOR_EXP_FUNC_S *pstExpFuncs)
{
    CAMERA_CHECK_POINTER(pstExpFuncs);

    memset(pstExpFuncs, 0, sizeof(AWB_SENSOR_EXP_FUNC_S));
    pstExpFuncs->pfnGetAwbDefault = CAMERA_GetAwbDefault;

    return EI_SUCCESS;
}

/****************************************************************************
 * callback structure                                                       *
 ****************************************************************************/

static EI_S32 CAMERA_CtxInit(VISS_DEV dev)
{
    SNS_STATE_S *pastSnsStateCtx = EI_NULL;

    SNS_GET_CTX(dev, pastSnsStateCtx);

    CAMERA_CHECK_POINTER(pastSnsStateCtx);

    memset(pastSnsStateCtx, 0, sizeof(SNS_STATE_S));

    pastSnsStateCtx->pstPowerUpAct      = s_stPowerUpAct;
    pastSnsStateCtx->pstPowerDownAct    = s_sPowerDownAct;
    pastSnsStateCtx->u8PwrUpActs        = ARRAY_SIZE(s_stPowerUpAct);
    pastSnsStateCtx->u8PwrDnActs        = ARRAY_SIZE(s_sPowerDownAct);

    return EI_SUCCESS;
}

static EI_VOID CAMERA_CtxExit(VISS_DEV dev)
{
    return ;
}

static EI_S32 CAMERA_RegisterVissCallback(VISS_DEV dev, SNS_TYPE_E enType)
{
    EI_S32 s32Ret;
    SENSOR_S stSns = {0};
    EI_U32 i;
    SNS_STATE_S *pstSnsState = EI_NULL;

    s32Ret = CAMERA_CtxInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    SNS_GET_CTX(dev, pstSnsState);

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsState->pstSnsAttr = &s_astSnsAttr[i];
            break;
        }
    }

    pstSnsState->enSnsType = enType;
    pstSnsState->Dev = dev;

    if (i >= ARRAY_SIZE(s_astSnsAttr)) {
        PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);
        return EI_FAILURE;
    }

    s32Ret = CAMERA_I2cInit(dev);
    if (EI_SUCCESS != s32Ret) {
        return EI_FAILURE;
    }

    stSns.stSnsAttrInfo.eSensorId = SNS_ID;
    stSns.stSnsAttrInfo.enDevType = DEV_TYPE;
    stSns.stSnsAttrInfo.pstSns = pstSnsState;

    s32Ret  = CAMERA_InitSensorExpFunction(&stSns.stSnsAttrInfo.stSnsExp);
    s32Ret |= VISS_SensorRegCallBack(dev, &stSns);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor register callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = CAMERA_OpenI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterVissCallback(VISS_DEV dev)
{
    EI_S32 s32Ret;
    SNS_STATE_S *pstSnsState = EI_NULL;

    SNS_GET_CTX(dev, pstSnsState);

    s32Ret = CAMERA_ExitI2c(pstSnsState);
    CAMERA_CHECK_SUCCESS(s32Ret);

    s32Ret = VISS_SensorUnRegCallBack(dev, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        PRT_VISS_ERR("%s sensor unregister callback function failed!\n", SNS_NAME);
        return s32Ret;
    }

    CAMERA_CtxExit(dev);

    return EI_SUCCESS;
}

static EI_S32 CAMERA_RegisterIspCallback(VISS_DEV Dev, ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;
    AE_SENSOR_REGISTER_S  stAeRegister;
    AWB_SENSOR_REGISTER_S stAwbRegister;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    SNS_SET_ISP_TO_VISS(dev, Dev);

    stAeRegister.SnsId = SNS_ID;
    stAwbRegister.SnsId = SNS_ID;

    s32Ret  = CAMERA_InitAeExpFunction(&stAeRegister.stSnsExp);
    s32Ret |= EI_MI_AE_SensorRegCallBack(dev, pstAeLib, &stAeRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret  = CAMERA_InitAwbExpFunction(&stAwbRegister.stSnsExp);
    s32Ret |= EI_MI_AWB_SensorRegCallBack(dev, pstAwbLib, &stAwbRegister);

    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s register callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_UnregisterIspCallback(ISP_DEV dev, ISP_3ALIB_S *pstAeLib, ISP_3ALIB_S *pstAwbLib)
{
    EI_S32 s32Ret;

    CAMERA_CHECK_POINTER(pstAeLib);
    CAMERA_CHECK_POINTER(pstAwbLib);

    s32Ret = EI_MI_AE_SensorUnRegCallBack(dev, pstAeLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to ae lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    s32Ret = EI_MI_AWB_SensorUnRegCallBack(dev, pstAwbLib, SNS_ID);
    if (EI_SUCCESS != s32Ret) {
        EI_TRACE_ISP(EI_DBG_ERR, "%s unregister callback function to awb lib failed!\n", SNS_NAME);
        return s32Ret;
    }

    return EI_SUCCESS;
}

static EI_S32 CAMERA_GetVissDevAttrBySns(SNS_TYPE_E enType,
    VISS_DEV_ATTR_S *pstVissDevAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissDevAttr->stSize          = pstSnsType->stSize;
            pstVissDevAttr->enWorkMode      = pstSnsType->enWorkMode;
            pstVissDevAttr->mClock          = pstSnsType->u32Mclock;
            pstVissDevAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissDevAttr->enWdrMode       = pstSnsType->enWdrMode;
            pstVissDevAttr->enIspWdrMode    = pstSnsType->enIspWdrMode;
            pstVissDevAttr->enRgbSeq        = pstSnsType->enRgbSeq;
            pstVissDevAttr->u32ModuleClk    = pstSnsType->u32ModuleClk;
            pstVissDevAttr->u32Fps          = pstSnsType->u32FrameRate;
            pstVissDevAttr->u32IspClk       = pstSnsType->u32IspClk;
            pstVissDevAttr->u32IppuClk      = pstSnsType->u32IppuClk;
            pstVissDevAttr->pcSnsName       = SNS_NAME;
            pstVissDevAttr->stDevCfg        = pstSnsType->stDevCfg;

            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this dev configuration", SNS_NAME);

    return EI_FAILURE;
}

static EI_S32 CAMERA_GetVissChnAttrBySns(SNS_TYPE_E enType,
    VISS_CHN_ATTR_S *pstVissChnAttr)
{
    EI_U32 i;
    const SNS_TYPE_ATTR_S *pstSnsType;

    for (i = 0; i < ARRAY_SIZE(s_astSnsAttr); i++) {
        if (enType == s_astSnsAttr[i].enSnsType) {
            pstSnsType = &s_astSnsAttr[i];
            pstVissChnAttr->stSize          = pstSnsType->stSize;
            pstVissChnAttr->enPixelFormat   = pstSnsType->enPixelFormat;
            pstVissChnAttr->stFrameRate.s32SrcFrameRate     = pstSnsType->u32FrameRate;
            return EI_SUCCESS;
        }
    }

    PRT_VISS_ERR("%s does not support this chn configuration", SNS_NAME);

    return EI_FAILURE;

}

CAMERA_OBJ_S stCameraImx335mipiObj = {
    .pfnRegisterVissCallback    = CAMERA_RegisterVissCallback,
    .pfnUnRegisterVissCallback  = CAMERA_UnregisterVissCallback,
    .pfnRegisterIspCallback     = CAMERA_RegisterIspCallback,
    .pfnUnRegisterIspCallback   = CAMERA_UnregisterIspCallback,
    .pfnGetVissDevAttrBySns     = CAMERA_GetVissDevAttrBySns,
    .pfnGetVissChnAttrBySns     = CAMERA_GetVissChnAttrBySns,
};


#ifdef __cplusplus
#if __cplusplus
}
#endif
#endif /* __cplusplus */

